<?php

namespace App\Logic;

use App\Model\Admin;
use App\Model\AdminLog;
use App\Model\ApplyAnchor;
use App\Model\ApplyExpert;
use App\Model\Article;
use App\Model\Game;
use App\Model\ImGroupMessage;
use App\Model\ImMessage;
use App\Model\Live;
use App\Model\LiveSessionGift;
use App\Model\Menu;
use App\Model\Play;
use App\Model\Project;
use App\Model\SyncFile;
use App\Model\Team;
use App\Model\Time;
use App\Model\User;
use App\Model\UserModelAnchor;
use App\Model\UserModelExpert;
use App\Utils\Log;
use Exception;
use Hyperf\Cache\Annotation\CacheAhead;
use Hyperf\Context\ApplicationContext;
use Hyperf\Context\Context;
use Hyperf\DbConnection\Db;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Redis\Redis;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use function Hyperf\Support\env;

class AdminLogic
{
    /**
     * 登录
     * @param $input
     * @return array
     * @throws Exception
     */
    public static function login($input): array
    {
        $maxLoginTimes = env('ADMIN_LOGIN_MAX_TIMES', 0);
        if ($maxLoginTimes) {
            $times = Time::query()->where('username', $input['username'])->first();
            if ($times) {
                if (date('Ymd') != date('Ymd', $times['last_time'])) {
                    Time::query()->where('username', $input['username'])->delete();
                    unset($times);
                } elseif ($times['times'] >= $maxLoginTimes) {
                    throw new Exception('今日错误次数过多，请明日再试');
                }
            }
        }

        $clientIp = Context::get('clientIp');
        $admin = Admin::query()->where('username', $input['username'])->first();
        if (!$admin || $admin['password'] !== create_password($input['password'], $admin['salt'], false)) {
            if (isset($times) && $times) {
                Time::query()->where('username', $input['username'])->update([
                    'times' => Db::raw('`times` + 1'),
                    'last_time' => \time(),
                    'last_ip' => $clientIp
                ]);
            } else {
                Time::create([
                    'username' => $input['username'],
                    'times' => 1,
                    'last_time' => \time(),
                    'last_ip' => $clientIp
                ]);
            }
            $curTimes = (int)Time::query()->where('username', $input['username'])->value('times');
            if ($admin) {
                AdminLog::create([
                    'userid' => $admin['userid'],
                    'username' => $admin['username'],
                    'action' => '登录账号 失败',
                    'action_data' => '[]',
                    'op_time' => \time()
                ]);
            }
            throw new Exception(sprintf('帐号或密码错误，剩余%d次机会', $maxLoginTimes - $curTimes));
        }
        $token = create_randomstr(32);
        try {
            $redis = ApplicationContext::getContainer()->get(Redis::class);
            $redis->hMSet('admin:token:' . $token, [
                'userId' => $admin['userid'],
                'userName' => $admin['username'],
                'userNick' => $admin['nickname'],
                'roleId' => $admin['roleid'],
                'lastTime' => $admin['last_time'],
                'lastIp' => $admin['last_ip']
            ]);
            AdminLog::create([
                'userid' => $admin['userid'],
                'username' => $admin['username'],
                'action' => '登录账号 成功',
                'action_data' => '[]',
                'op_time' => \time()
            ]);
            Time::query()->where('username', $input['username'])->delete();
            return [
                'userId' => $admin['userid'],
                'userName' => $admin['username'],
                'userNick' => $admin['userNick'],
                'roleId' => $admin['roleid'],
                'token' => $token
            ];
        } catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) {
            throw new Exception('系统异常，请稍后再试');
        }
    }

    /**
     * 退出登录
     * @return true
     * @throws Exception
     */
    public static function logout(): true
    {
        try {
            $container = ApplicationContext::getContainer();
            $request = $container->get(RequestInterface::class);
            $token = $request->hasHeader('token') ? $request->getHeaderLine('token') : '';
            var_dump($token);
            if (!empty($token)) {
                echo 'admin:token:' . $token;
                $redis = $container->get(Redis::class);
                $redis->del('admin:token:' . $token);
                $userId = Context::get('userId', 0);
                $userName = Context::get('userName', '');
                if ($userId && $userName) {
                    AdminLog::create([
                        'userid' => $userId,
                        'username' => $userName,
                        'action' => '退出登录',
                        'op_time' => \time()
                    ]);
                }
            }
            return true;
        } catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) {
            throw new Exception('系统异常，请稍后再试');
        }
    }

    /**
     * 列表
     * @param $input
     * @return array
     */
    public static function lists($input): array
    {
        [$pageNum, $pageSize, $offset] = parsePageParams($input);
        $total = Admin::query()->where('status', '<>', 'delete')->count();
        if ($total) {
            $records = Admin::query()->where('status', '<>', 'delete')->orderBy('userid', 'asc')->offset($offset)->limit($pageSize)->get()->toArray();
        }
        return [
            'total' => $total,
            'pages' => ceil($total / $pageSize),
            'records' => $records ?? []
        ];
    }

    /**
     * 添加管理员
     * @throws Exception
     */
    public static function add($input): array
    {
        if (Admin::query()->where('username', $input['username'])->exists()) {
            throw new Exception('该登录用户名不可用');
        }
        $salt = create_randomstr(6);
        $password = create_password($input['password'], $salt, false);
        $data = [
            'roleid' => $input['roleid'] ?? 1,
            'username' => $input['username'],
            'nickname' => $input['nickname'],
            'password' => $password,
            'salt' => $salt,
            'op_userid' => Context::get('userId'),
            'op_username' => Context::get('userName'),
            'op_time' => time(),
            'last_ip' => Context::get('clientIp'),
            'last_time' => time(),
            'status' => 'ok',
        ];
        $admin = Admin::create($data);
        if (!$data) {
            throw new Exception('添加失败');
        }
        return $admin->toArray();
    }

    /**
     * 修改管理员
     * @throws Exception
     */
    public static function edit($userId, $input): true
    {
        $admin = Admin::query()->where('userid', $userId)->first();
        if (!$admin) {
            throw new Exception('管理员不存在');
        }
        $data = [];
        if (!empty($input['nickname'])) {
            $data['nickname'] = $input['nickname'];
        }
        if (!empty($input['password'])) {
            $data['salt'] = create_randomstr();
            $data['password'] = create_password($input['password'], $data['salt'], false);
        }
        if ($userId != Context::get('userId') && !empty($input['status']) && in_array($input['status'], ['locked', 'ok'])) {
            $data['status'] = $input['status'];
        }
        if (!empty($data)) {
            Admin::query()->where('userid', $userId)->update($data);
        }
        return true;
    }

    /**
     * 删除管理员
     * @param $userId
     * @return true
     * @throws Exception
     */
    public static function delete($userId): true
    {
        if ($userId == Context::get('userId')) {
            throw new Exception('不能删除当前管理员');
        }
        Admin::query()->where('userid', $userId)->update(['status' => 'delete']);
        return true;
    }

    /**
     * 锁定管理员
     * @throws Exception
     */
    public static function lock($userId): true
    {
        if ($userId == Context::get('userId')) {
            throw new Exception('不能锁定当前管理员');
        }
        Admin::query()->where('userid', $userId)->update(['status' => 'locked']);
        return true;
    }

    /**
     * 解锁管理员
     * @throws Exception
     */
    public static function unlock($userId): true
    {
        if ($userId == Context::get('userId')) {
            throw new Exception('不能解锁当前管理员');
        }
        Admin::query()->where('userid', $userId)->update(['status' => 'ok']);
        return true;
    }

    /**
     * 修改当前管理员密码
     * @param $password
     * @return true
     */
    public static function password($password): true
    {
        $userId = Context::get('userId', 0);
        $salt = create_randomstr();
        $password = create_password($password, $salt, false);
        Admin::query()->where('userid', $userId)->update(['password' => $password, 'salt' => $salt]);
        try {
            self::logout();
        } catch (Exception $e) {
            Log::error(sprintf('退出登录异常:%s', $e->getMessage()));
        }
        return true;
    }

    /**
     * 总览
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public static function statistics(): array
    {
        $container = ApplicationContext::getContainer();
        $lastTime = Context::get('lastTime', 0);
        return [
            'quickMenu' => Menu::query()->where(['type' => 1, 'is_quick' => 1])->get(['id', 'name', 'style', 'url'])->toArray(),
            'statInfo' => self::getStatInfo(),
            'sysInfo' => [
                '您的IP地址' => getClientIp(),
                '上次登录' => $lastTime ? date('Y-m-d H:i:s', $lastTime) : '-',
                '服务器IP地址' => $container->get(RequestInterface::class)->getServerParams()['SERVER_ADDR'] ?? '未知',
                '服务器时间' => date('Y-m-d H:i:s'),
                '操作系统及PHP版本' => PHP_OS . ' / PHP v' . PHP_VERSION . (@ini_get('safe_mode') ? ' Safe Mode' : ''),
                '已安装PHP扩展' => implode(' ', get_loaded_extensions()),
                'Swoole版本' => swoole_version(),
                'Hyperf版本' => '3.1.23',
            ],
        ];
    }

    /**
     * 统计
     * @return array[]
     */
    public static function getStatInfo(): array
    {
        return [
            [
                'name' => '用户总数',
                'value' => User::query()->count(),
                'desc' => '',
                'sub' => ''
            ],
            [
                'name' => '今日注册',
                'value' => User::whereDate('reg_time', date('Y-m-d'))->count(),
                'desc' => '',
                'sub' => ''
            ],
            [
                'name' => '本月注册',
                'value' => User::whereYear('reg_time', date('Y'))->whereMonth('reg_time', date('m'))->count(),
                'desc' => '',
                'sub' => ''
            ],
            [
                'name' => '当前在线',
                'value' => 0,
                'desc' => '',
                'sub' => '',
            ],
            [
                'name' => '主播总数',
                'value' => UserModelAnchor::count(),
                'desc' => '',
                'sub' => '',
            ],
            [
                'name' => '正在直播',
                'value' => Live::where('status', 2)->count(),
                'desc' => '',
                'sub' => '',
            ],
            [
                'name' => '今日打赏',
                'value' => LiveSessionGift::where('idx_date', date('Ymd'))->sum('amount'),
                'desc' => '',
                'sub' => '',
            ],
            [
                'name' => '待处理主播入驻',
                'value' => ApplyAnchor::where('audit_status', 0)->count(),
                'desc' => '',
                'sub' => '',
            ],
            [
                'name' => '比赛总数',
                'value' => Play::count(),
                'desc' => '',
                'sub' => '',
            ],
            [
                'name' => '赛事总数',
                'value' => Game::count(),
                'desc' => '',
                'sub' => '',
            ],
            [
                'name' => '球队总数',
                'value' => Team::count(),
                'desc' => '',
                'sub' => '',
            ],
            [
                'name' => '正在比赛',
                'value' => Play::where('match_status', 2)->count(),
                'desc' => '',
                'sub' => '',
            ],
            [
                'name' => '专家总数',
                'value' => UserModelExpert::count(),
                'desc' => '',
                'sub' => '',
            ],
            [
                'name' => '累计方案',
                'value' => Project::count(),
                'desc' => '',
                'sub' => '',
            ],
            [
                'name' => '待处理专家入驻',
                'value' => ApplyExpert::where('audit_status', 0)->count(),
                'desc' => '',
                'sub' => '',
            ],
            [
                'name' => '文章总数',
                'value' => Article::count(),
                'desc' => '',
                'sub' => '',
            ],
            [
                'name' => '消息总数',
                'value' => ImGroupMessage::count() + ImMessage::count(),
                'desc' => '',
                'sub' => '',
            ],
            [
                'name' => '累计附件',
                'value' => SyncFile::count(),
                'desc' => '',
                'sub' => '',
            ],
            [
                'name' => '日志总量',
                'value' => self::getLogSize(),
                'desc' => '',
                'sub' => '',
            ],
        ];
    }

    /**
     * 日志文件大小
     * @return string
     */
    #[CacheAhead(prefix: "logSize", ttl: 300, aheadSeconds: 30, lockSeconds: 10)]
    public static function getLogSize(): string
    {
        $logDir = BASE_PATH . '/runtime/logs';
        $totalSize = 0;
        // 检查目录是否存在
        if (is_dir($logDir)) {
            $files = scandir($logDir);
            foreach ($files as $file) {
                if ($file !== '.' && $file !== '..') {
                    $filePath = $logDir . '/' . $file;
                    // 检查是否是文件，并计算文件大小
                    if (is_file($filePath)) {
                        $totalSize += filesize($filePath);
                    }
                }
            }
        }
        return formatSize($totalSize);
    }
}